package com.ymx.darling.executor.mapping.relation;

import com.ymx.darling.bean.entity.BeanInfo;
import com.ymx.darling.bean.entity.FieldInfo;
import com.ymx.darling.bean.sql.Statement;
import com.ymx.darling.exception.EntityException;
import com.ymx.darling.executor.Executor;
import com.ymx.darling.executor.mapping.relation.annotation.RelationOneToMany;
import com.ymx.darling.session.setting.relation.RelationEntity;
import com.ymx.darling.util.ReflectUtil;
import com.ymx.darling.util.StringUtil;
import com.ymx.darling.wrapper.QueryWrapper;
import com.ymx.darling.wrapper.build.SelectBuilder;
import com.ymx.darling.bean.sql.SqlStatement;

import java.util.*;

/**
 * 关联一对多执行器
 */
public class RelationOneToManyLoader extends RelationLoader{
    private final RelationOneToMany oneToMany;

    public RelationOneToManyLoader(RelationOneToMany oneToMany) {
        this.oneToMany = oneToMany;
    }

    @Override
    public void invoke(Statement statement, RelationEntity relationEntity, List<?> resultList) {
        // 构建目标查询的sql
        SqlStatement sqlStatement = this.buildTargetQuerySql(statement.getBeanInfo(), relationEntity.getBeanInfo(), statement.getNestedQueryParam(), resultList);
        // 构建statement
        Statement fieldQueryStatement = this.createStatement(statement, relationEntity, sqlStatement);
        // 执行sql 并将结果集按照提前指定好的字段放入Map中
        Map<?, List<Object>> resultMap = this.executor(fieldQueryStatement, relationEntity.getRelationFieldInfo());
        // 完成赋值
        this.putValueToResult(statement.getBeanInfo(), relationEntity, resultList, resultMap);
    }


    /**
     * 构建目标表的sql
     * @param selfBeanInfo 当前表实体的BeanInfo
     * @param targetBeanInfo 目标表实体的BeanInfo
     * @param nestedQueryParam 内嵌参数
     * @param resultList 主查询结果集
     * @return SqlStatement
     */
    private SqlStatement buildTargetQuerySql(BeanInfo selfBeanInfo, BeanInfo targetBeanInfo, Map<String, Object> nestedQueryParam, List<?> resultList) {
        // 根据关联数据创建QueryWrapper实例
        QueryWrapper queryWrapper = this.createTargetTableQueryWrapper(selfBeanInfo, targetBeanInfo, resultList);
        // 判断配置外部条件
        this.applyConditionAndOrderBy(queryWrapper, oneToMany.condition(), oneToMany.orderBy(), nestedQueryParam);
        // 返回构建后的sql及其参数
        return new SelectBuilder().buildSelect(queryWrapper, targetBeanInfo);
    }


    /**
     * 执行sql并将结果集按照给定字段的值封装为一个Map
     * @param statement statement
     * @return 返回Map集合 key-给定字段的值 value-实体对象集合
     */
    private Map<?,List<Object>> executor(Statement statement, RelationFieldInfo relationFieldInfo) {
        Executor executor = statement.getExecutor();
        List<Object> resultList = executor.queryList(statement);
        Map<Object, List<Object>> resultMap = new HashMap<>(resultList.size());
        BeanInfo beanInfo = statement.getBeanInfo();
        String targetColumn = this.getTargetColumn(beanInfo);
        FieldInfo targetFieldInfo = beanInfo.getSimpleColumnMap().get(targetColumn);
        // 构建结果集
        resultList.forEach(result -> {
            Object key = ReflectUtil.getValue(targetFieldInfo.getField(), result);
            List<Object> itemList = resultMap.get(key);
            if (Objects.isNull(itemList)) {
                Class<?> relationCollectionType = relationFieldInfo.getField().getType();
                itemList = ReflectUtil.newInstanceList(relationCollectionType);
                resultMap.put(key, itemList);
            }
            itemList.add(this.getValueWithTargetClass(result));
        });
        return resultMap;
    }


    protected FieldInfo getSelfColumn(BeanInfo beanInfo) {
        Map<String, FieldInfo> columnInfoMap = beanInfo.getFieldMap();
        String selfColumn = oneToMany.selfField();

        if (StringUtil.isNoNull(selfColumn)) {
            if (!columnInfoMap.containsKey(selfColumn)) {
                throw new EntityException(String.format("字段'%s'在类'%s'中不存在", selfColumn, beanInfo.getModule().getName()));
            }
            return columnInfoMap.get(selfColumn);
        } else {
            FieldInfo idFieldInfo = beanInfo.getIdColumnInfo();
            if (Objects.isNull(idFieldInfo)) {
                throw new EntityException(String.format("类%s中缺少id字段,当@RelationOneToMany注解的selftColumn缺省时会将被@Id标注的字段名当做默认名", beanInfo.getModule().getName()));
            }
            return idFieldInfo;
        }
    }

    @Override
    public Class<?> getTargetClass() {
        return oneToMany.targetClass();
    }


    protected String getTargetColumn(BeanInfo beanInfo) {
        String targetColumn = oneToMany.targetField();
        FieldInfo fieldInfo = beanInfo.getFieldMap().get(targetColumn);
        if (Objects.isNull(fieldInfo)) {
            throw new EntityException(String.format("类'%s'关联查询时指定的关联字段'%s'不存在", beanInfo.getModule().getName(), targetColumn));
        }
        return fieldInfo.getColumn();
    }


    protected String[] getSelectColumns() {
        return oneToMany.selectColumns();
    }
}
